package cn.iocoder.yudao.module.reading.service.bookset;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.reading.controller.admin.bookset.vo.BookSetCreateReqVO;
import cn.iocoder.yudao.module.reading.controller.admin.bookset.vo.BookSetUpdateReqVO;
import cn.iocoder.yudao.module.reading.controller.app.book.vo.PictureBookRespVO;
import cn.iocoder.yudao.module.reading.controller.app.bookset.vo.BookSetDetailRespVO;
import cn.iocoder.yudao.module.reading.controller.app.bookset.vo.BookSetPageReqVO;
import cn.iocoder.yudao.module.reading.convert.bookset.BookSetConvert;
import cn.iocoder.yudao.module.reading.dal.dataobject.book.PictureBookDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.bookset.BookSetDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.hidden.UserHiddenItemsDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.record.ReadingRecordDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.recyclebin.UserRecycleBinDO;
import cn.iocoder.yudao.module.reading.dal.mysql.book.PictureBookMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.bookset.BookSetMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.hidden.UserHiddenItemsMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.record.ReadingRecordMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.recyclebin.UserRecycleBinMapper;
import cn.iocoder.yudao.module.reading.framework.util.StaticResourceUrlUtils;
import cn.iocoder.yudao.module.reading.service.file.ReadingFileService;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.reading.enums.ErrorCodeConstants.BOOK_SET_NOT_EXISTS;

/**
 * 绘本集 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class BookSetServiceImpl implements BookSetService {

    @Resource
    private BookSetMapper bookSetMapper;
    @Resource
    private PictureBookMapper pictureBookMapper;
    @Resource
    private ReadingRecordMapper readingRecordMapper;
    @Resource
    private UserRecycleBinMapper userRecycleBinMapper;
    @Resource
    private UserHiddenItemsMapper userHiddenItemsMapper;
    @Resource
    private StaticResourceUrlUtils staticResourceUrlUtils;
    @Resource
    private ReadingFileService readingFileService;

    @Override
    public BookSetDO getBookSet(Long id) {
        BookSetDO bookSet = bookSetMapper.selectById(id);
        if (bookSet == null) {
            throw exception(BOOK_SET_NOT_EXISTS);
        }
        return bookSet;
    }

    @Override
    public BookSetDetailRespVO getBookSetDetail(Long id, Long userId) {
        // 1. 获取绘本集信息
        BookSetDO bookSet = getBookSet(id);

        // 2. 获取绘本列表
        List<PictureBookDO> books = pictureBookMapper.selectByBookSetId(id);

        // 3. 获取用户阅读记录
        Map<Long, ReadingRecordDO> readingRecords = Map.of();
        if (CollUtil.isNotEmpty(books) && userId != null) {
            List<Long> bookIds = books.stream().map(PictureBookDO::getId).collect(Collectors.toList());
            List<ReadingRecordDO> records = readingRecordMapper.selectByUserIdAndBookIds(userId, bookIds);
            readingRecords = records.stream().collect(Collectors.toMap(ReadingRecordDO::getBookId, record -> record));
        }

        // 4. 构建响应
        BookSetDetailRespVO result = BookSetConvert.INSTANCE.convertDetail(bookSet);

        // 5. 设置绘本列表
        if (CollUtil.isNotEmpty(books)) {
            List<PictureBookRespVO> bookList = BookSetConvert.INSTANCE.convertBookList(books, readingRecords, bookSet.getTitle());
            result.setBooks(bookList);
        }

        // 6. 转换URL
        result.convertUrls();

        return result;
    }

    @Override
    public PageResult<BookSetDO> getBookSetPage(cn.iocoder.yudao.module.reading.controller.app.bookset.vo.BookSetPageReqVO pageReqVO, Long userId) {
        PageResult<BookSetDO> result = bookSetMapper.selectPage(pageReqVO);
        if (userId != null) {
            result = filterRecycleBinBookSetsWithCorrectTotal(result, pageReqVO, userId);
        }
        return result;
    }

    @Override
    public PageResult<BookSetDO> getBookSetPage(cn.iocoder.yudao.module.reading.controller.admin.bookset.vo.BookSetPageReqVO pageReqVO) {
        return bookSetMapper.selectPage(pageReqVO);
    }

    @Override
    public List<BookSetDO> getRecommendedBookSets(String language, Long categoryId, Integer limit, Long userId) {
        if (limit == null) {
            limit = 10; // 默认限制10个
        }
        List<BookSetDO> result = bookSetMapper.selectRecommendedByLanguageAndCategory(language, categoryId, limit);
        if (userId != null) {
            result = filterRecycleBinBookSets(result, userId);
        }
        return result;
    }

    @Override
    public List<BookSetDO> getBookSetsByCategory(Long categoryId, Integer limit, Long userId) {
        List<BookSetDO> result = bookSetMapper.selectByCategoryId(categoryId, limit);
        if (userId != null) {
            result = filterRecycleBinBookSets(result, userId);
        }
        return result;
    }

    @Override
    public List<BookSetDO> searchBookSets(String keyword, String language, Long userId) {
        List<BookSetDO> result = bookSetMapper.searchBookSets(keyword, language);
        if (userId != null) {
            result = filterRecycleBinBookSets(result, userId);
        }
        return result;
    }

    @Override
    public PageResult<BookSetDO> searchBookSets(String keyword, String language, Integer pageNo, Integer pageSize, Long userId) {
        // 创建分页参数
        PageParam pageParam = new PageParam();
        pageParam.setPageNo(pageNo);
        pageParam.setPageSize(pageSize);

        // 执行分页搜索
        PageResult<BookSetDO> result = bookSetMapper.searchBookSetsPage(keyword, language, pageParam);

        // 如果有用户ID，过滤回收站数据并重新计算总数
        if (userId != null) {
            // 获取过滤前的所有数据（用于计算正确的总数）
            List<BookSetDO> allResults = bookSetMapper.searchBookSets(keyword, language);
            List<BookSetDO> filteredAllResults = filterRecycleBinBookSets(allResults, userId);

            // 过滤当前页的数据
            List<BookSetDO> filteredPageResults = filterRecycleBinBookSets(result.getList(), userId);

            // 创建新的分页结果，使用正确的总数
            return new PageResult<>(filteredPageResults, (long) filteredAllResults.size());
        }

        return result;
    }

    // =============================================
    // 向后兼容的方法实现（不过滤回收站）
    // =============================================

    @Override
    public List<BookSetDO> getRecommendedBookSets(String language, Long categoryId, Integer limit) {
        return getRecommendedBookSets(language, categoryId, limit, null);
    }

    @Override
    public List<BookSetDO> getBookSetsByCategory(Long categoryId, Integer limit) {
        return getBookSetsByCategory(categoryId, limit, null);
    }

    @Override
    public List<BookSetDO> searchBookSets(String keyword, String language) {
        return searchBookSets(keyword, language, null);
    }

    // =============================================
    // 管理员操作方法实现
    // =============================================

    @Override
    public Long createBookSet(BookSetCreateReqVO createReqVO) {
        // 转换为DO对象
        BookSetDO bookSet = BeanUtils.toBean(createReqVO, BookSetDO.class);
        bookSet.setBookCount(0); // 初始绘本数量为0

        // 处理封面URL：将完整URL转换为相对路径存储
        if (StrUtil.isNotEmpty(bookSet.getCover())) {
            String relativePath = staticResourceUrlUtils.toRelativePath(bookSet.getCover());
            bookSet.setCover(relativePath);
            log.debug("绘本集封面URL标准化: {} -> {}", createReqVO.getCover(), relativePath);
        }

        // 插入数据库
        bookSetMapper.insert(bookSet);

        // 打印文件路径信息到控制台
        log.info("=== 绘本集创建成功，文件路径信息 ===");
        log.info("绘本集ID: {}", bookSet.getId());
        log.info("绘本集封面路径: book-sets/covers/{}/", bookSet.getId());
        log.info("绘本文件路径: books/covers/set-{}/book-{}/", bookSet.getId(), "{bookId}");
        log.info("绘本页面路径: books/pages/set-{}/book-{}/", bookSet.getId(), "{bookId}");
        log.info("绘本音频路径: books/audios/set-{}/book-{}/", bookSet.getId(), "{bookId}");
        log.info("================================");

        return bookSet.getId();
    }

    @Override
    public void updateBookSet(BookSetUpdateReqVO updateReqVO) {
        // 校验存在
        validateBookSetExists(updateReqVO.getId());

        // 获取现有绘本集信息
        BookSetDO existingBookSet = bookSetMapper.selectById(updateReqVO.getId());

        // 转换为DO对象
        BookSetDO updateObj = BeanUtils.toBean(updateReqVO, BookSetDO.class);

        // 处理封面URL：将完整URL转换为相对路径存储
        String oldCoverPath = existingBookSet.getCover();
        if (StrUtil.isNotEmpty(updateObj.getCover())) {
            String relativePath = staticResourceUrlUtils.toRelativePath(updateObj.getCover());
            updateObj.setCover(relativePath);
            log.debug("绘本集封面URL标准化: {} -> {}", updateReqVO.getCover(), relativePath);

            // 如果封面路径发生变化，删除旧文件
            if (StrUtil.isNotEmpty(oldCoverPath) && !oldCoverPath.equals(relativePath)) {
                try {
                    readingFileService.deleteFile(oldCoverPath);
                    log.info("已删除旧的绘本集封面文件: {}", oldCoverPath);
                } catch (Exception e) {
                    log.warn("删除旧封面文件失败: {}", oldCoverPath, e);
                }
            }
        }

        // 更新数据库
        bookSetMapper.updateById(updateObj);

        log.info("绘本集更新成功，ID: {}", updateReqVO.getId());
    }

    @Override
    public void deleteBookSet(Long id) {
        // 校验存在
        validateBookSetExists(id);

        // 删除绘本集
        bookSetMapper.deleteById(id);

        log.info("绘本集删除成功，ID: {}", id);
    }

    @Override
    public Long getNextBookSetId() {
        // 获取下一个自增ID
        // 这里使用一个简单的方法：查询当前最大ID + 1
        Long maxId = bookSetMapper.selectMaxId();
        Long nextId = (maxId == null ? 0 : maxId) + 1;

        log.info("获取下一个绘本集ID: {}", nextId);
        return nextId;
    }

    @Override
    public void updateBookSetBookCount(Long bookSetId) {
        // 校验绘本集是否存在
        validateBookSetExists(bookSetId);

        // 统计该绘本集的绘本数量
        int bookCount = pictureBookMapper.selectByBookSetId(bookSetId).size();

        // 更新绘本集的绘本数量
        BookSetDO updateObj = new BookSetDO();
        updateObj.setId(bookSetId);
        updateObj.setBookCount(bookCount);
        bookSetMapper.updateById(updateObj);

        log.info("更新绘本集绘本数量成功，绘本集ID: {}, 绘本数量: {}", bookSetId, bookCount);
    }

    @Override
    public List<BookSetDO> getBookSetList(String language, String title) {
        return bookSetMapper.selectList(language, title);
    }

    @Override
    @Transactional
    public void batchDeleteBookSet(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return;
        }

        // 校验绘本集存在
        for (Long id : ids) {
            validateBookSetExists(id);
        }

        // 批量删除
        bookSetMapper.deleteBatchIds(ids);

        log.info("批量删除绘本集成功，IDs: {}", ids);
    }

    @Override
    @Transactional
    public void batchUpdateBookSetStatus(List<Long> ids, Boolean isActive) {
        if (ids == null || ids.isEmpty()) {
            return;
        }

        // 校验绘本集存在
        for (Long id : ids) {
            validateBookSetExists(id);
        }

        // 批量更新状态
        bookSetMapper.updateBatchStatus(ids, isActive);

        log.info("批量更新绘本集状态成功，IDs: {}, 状态: {}", ids, isActive);
    }

    /**
     * 校验绘本集是否存在
     */
    private void validateBookSetExists(Long id) {
        if (bookSetMapper.selectById(id) == null) {
            throw new IllegalArgumentException("绘本集不存在");
        }
    }

    /**
     * 过滤用户回收站中的绘本集（分页结果）
     */
    private PageResult<BookSetDO> filterRecycleBinBookSets(PageResult<BookSetDO> pageResult, Long userId) {
        if (pageResult == null || CollUtil.isEmpty(pageResult.getList()) || userId == null) {
            return pageResult;
        }

        List<BookSetDO> filteredList = filterRecycleBinBookSets(pageResult.getList(), userId);
        return new PageResult<>(filteredList, pageResult.getTotal());
    }

    /**
     * 过滤用户回收站中的绘本集（分页结果，重新计算总数）
     */
    private PageResult<BookSetDO> filterRecycleBinBookSetsWithCorrectTotal(PageResult<BookSetDO> pageResult,
            cn.iocoder.yudao.module.reading.controller.app.bookset.vo.BookSetPageReqVO pageReqVO, Long userId) {
        if (pageResult == null || userId == null) {
            return pageResult;
        }

        // 过滤当前页的数据
        List<BookSetDO> filteredPageList = filterRecycleBinBookSets(pageResult.getList(), userId);

        // 获取所有符合条件的数据（不分页）来计算正确的总数
        cn.iocoder.yudao.module.reading.controller.app.bookset.vo.BookSetPageReqVO allDataReqVO =
                new cn.iocoder.yudao.module.reading.controller.app.bookset.vo.BookSetPageReqVO();
        allDataReqVO.setCategoryId(pageReqVO.getCategoryId());
        allDataReqVO.setLang(pageReqVO.getLang());
        allDataReqVO.setPageNo(1);
        allDataReqVO.setPageSize(Integer.MAX_VALUE); // 获取所有数据

        PageResult<BookSetDO> allDataResult = bookSetMapper.selectPage(allDataReqVO);
        List<BookSetDO> filteredAllData = filterRecycleBinBookSets(allDataResult.getList(), userId);

        return new PageResult<>(filteredPageList, (long) filteredAllData.size());
    }

    /**
     * 过滤用户隐藏的绘本集（包括回收站和彻底删除的）
     */
    private List<BookSetDO> filterRecycleBinBookSets(List<BookSetDO> bookSets, Long userId) {
        if (CollUtil.isEmpty(bookSets) || userId == null) {
            return bookSets;
        }

        // 获取用户回收站中的绘本集ID列表
        List<UserRecycleBinDO> recycleBinList = userRecycleBinMapper.selectListByUserId(userId);
        java.util.Set<Long> recycleBinBookSetIds = recycleBinList.stream()
                .filter(item -> "book_set".equals(item.getItemType()))
                .map(UserRecycleBinDO::getItemId)
                .collect(java.util.stream.Collectors.toSet());

        // 获取用户隐藏的绘本集ID列表
        List<UserHiddenItemsDO> hiddenItemsList = userHiddenItemsMapper.selectListByUserIdAndType(userId, "book_set");
        java.util.Set<Long> hiddenBookSetIds = hiddenItemsList.stream()
                .map(UserHiddenItemsDO::getItemId)
                .collect(java.util.stream.Collectors.toSet());

        // 过滤掉回收站和隐藏的绘本集
        return bookSets.stream()
                .filter(bookSet -> !recycleBinBookSetIds.contains(bookSet.getId())
                                && !hiddenBookSetIds.contains(bookSet.getId()))
                .collect(java.util.stream.Collectors.toList());
    }

}
